﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ProjectStorageLib.Project
{
    public class ProjectsManager : DatabaseEntities
    {
        ProjectFilter filter;
        public ProjectsManager(ProjectFilter filter) : base() {
            this.filter = filter;
        }


        public IEnumerable<ProjectManager> GetResult()
        {
            return this.ent.Projects.Where(p => p.UserID == filter.UserID).ToList()
                .Select(p => new ProjectManager(this, p));
        }

        public IEnumerable<ProjectManager> GetAllProjects()
        {
            return this.ent.Projects.ToList().Select(p => new ProjectManager(this, p));
        }

        protected override void Dispose(bool flag)
        {
        }

        /// <summary>
        /// The Great Calculation method
        /// </summary>
        /// <returns></returns>
        public IEnumerable<ProjectManager> GetSimilarProjects()
        {
            List<ProjectManager> pmList = new List<ProjectManager>();

            var allProjects = this.ent.Projects;
            var factorValues = this.filter.FactorValues;
            var factorMandatory = this.filter.FactorMandatory;

            int factorsCount = this.filter.FactorValues.Count;

            //get factors for entered user values
            var factors = from f in ent.Factors
                          where factorValues.Keys.Contains(f.FactorID)
                          select f;


            foreach (var project in allProjects)
            {
                double projectCoef = 0;
                foreach (var factor in factors)
                {
                    var factorValue = project.FactorValues.SingleOrDefault(fv => fv.FactorID == factor.FactorID);
                    
                    //get scale size in a very strange way!
                    var scaleSize = (from fs in ent.FactorScales
                                     where fs.FactorID == factor.FactorID
                                     orderby fs.Order
                                     select fs).ToList().Last().Order.Value;

                    if (!factor.ScaleType)//ako e nominalna
                    {
                        //ako ima stoinost za tozi factor
                        if (factorValue != null)
                        {
                            decimal fsID = factorValues[factorValue.FactorID];
                            var chosenFactorValue = (from fs in ent.FactorScales
                                                     where fs.FactorScaleID == fsID
                                                     select fs.Order.Value).Single();

                            //ako stoinostta e ravna s izbranata
                            if (factorValue.FactorScale.Order.Value == chosenFactorValue)
                            {
                                projectCoef++;
                            }
                            else
                            {
                                if (factorMandatory[factorValue.FactorID])
                                    continue;

                                projectCoef += (double)1 / scaleSize;
                            }
                        }
                        //ako nqma ne uveli4avame koeficienta
                    }
                    else
                    {
                        //ako ima stoinost za tozi factor
                        if (factorValue != null)
                        {
                            decimal fsID = factorValues[factorValue.FactorID];
                            var chosenFactorValue = (from fs in ent.FactorScales
                                                     where fs.FactorScaleID == fsID
                                                     select fs.Order.Value).Single();

                            if (factorMandatory[factorValue.FactorID] && factorValue.FactorScale.Order.Value != chosenFactorValue)
                                continue;
                            //1 - (|x-y| / size - 1)
                            projectCoef += 1.0 - ((double)Math.Abs(factorValue.FactorScale.Order.Value - chosenFactorValue)) / (scaleSize - 1);
                        }
                        else
                        {
                            if (factorMandatory[factor.FactorID])
                                continue;
                            projectCoef += (double)1 / scaleSize;
                        }
                    }
                }

                double acceptanceCoef = 0.5;
                var dbCoef = this.ent.Configuration.FirstOrDefault();
                double parsedCoef;
                if (dbCoef!=null && double.TryParse(dbCoef.Value, out parsedCoef))
                {
                    acceptanceCoef = parsedCoef;
                }

                double similarityCoef = projectCoef / factorsCount;

                if (similarityCoef > acceptanceCoef)
	            {
		            pmList.Add(new ProjectManager(this, project)); 
	            }
            }

            return pmList;
        }
    }
}
